home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource5
/
355_01
/
slk1.exe
/
SHERLOCK
/
PRF.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-07-22
|
11KB
|
459 lines
; Profiler for Sherlock--low level routines
;
; WARNING! use this file at your own risk. See further warnings below.
;
; source: prf.asm
; started: November 10, 1986
; version: July 22, 1988
;
;
; Copyright (C) 1987, 1988 by Edward K. Ream.
; All Rights reserved.
;
;
; This file contains an interrupt handler for timing interrupts,
; and routines to install and de-install the handler.
;
; NOTE: This file is required only if the TIME_STATS variable is
; #define'd in the file SHERLOCK.C.
;
; NOTE: Assemble this file with the Microsoft MASM assembler and
; link this file with the Microsoft or TURBO C linkers.
; Use the /MX and /ML options when assembling this file.
;
; NOTE: Use the /DNEAR option on the MASM command line when producing
; a .obj file to be used with memory models with small code
; space, namely the Microsoft small and compact models. Do NOT
; use the /DNEAR option when using the other memory models.
;
; WARNING! You must MAKE SURE that you change this code correctly
; reflects the memory model you are using in your C code.
; If you get this wrong, the code will die a quick death.
;
; WARNING! USE THIS CODE AT YOUR OWN RISK. This code may cause
; your system to hang. This code contains potential machine
; dependencies. See further warnings below. However, this
; code has been tested on both PC clones and AT clones.
;
; WARNING! The code changes interrupts 33-36 in an attempt to trap
; ALL exit points from the program. If this attempt is not
; successful, the system will hang and a reboot is the only
; way out. DO NOT, repeat DO NOT, use this code if that
; possibility is unacceptable!!!
;
; WARNING! The code messes with the timing rate of the system clock to
; increase the number of timing interrupts without changing
; number of 'tick' interrupts visible to the rest of the
; system. To do this, it must touch the underlying clock
; hardware. In particular this code fiddles with the 8251
; timer chip. THIS CODE MAY NOT WORK if that chip does not
; exist on your machine.
;
TITLE prf.asm
DGROUP GROUP _DATA
ASSUME ds:DGROUP
;
; Declare variables which are defined in sherlock.c
; (sl_count and sl_speed).
; Also define local variables.
;
_DATA SEGMENT WORD PUBLIC 'DATA'
EXTRN _sl_count:DWORD
EXTRN _sl_speed:WORD
timer_count dw 1 ;internal timer count
timer_speed dw 1 ;internal timer speed
installed db 0 ;true = routines installed
_DATA ENDS
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME cs:_TEXT
;
; Storage area for saved interrupt vectors.
;
; The interrupt installation routine, sl_von, saves the old value of
; the interrupt vectors here. The de-initialization routine, sl_voff,
; restores the vectors using these values.
;
; WARNING! We must attempt to trap ALL exits from the program, because
; we can not rely on the program itself to call sl_voff.
; After all, we ARE debugging, so aborting the program must be
; expected. THIS CREATES A PROBLEM, because if the program
; ever terminates without sl_von being called, the interrupt
; handlers will not be restored and the system will hang.
;
; These vectors MUST be in the code segment; Indeed, when we do the
; jump-indirect that gets us to the machine's routines, we must have
; all the processor registers and flags restored to their original
; values. If we change ds, (in order to pick these out of the data
; segment and do the indirect jump), there's no way to change ds back
; again to whatever the caller had it.
;
; The fact that these vectors are in the code segment instead of the
; data segment makes the code below much more tricky than usual.
; Be warned. Do not change the code in sl_von and sl_voff without
; careful thought.
;
old_8 label DWORD ;Tick interrupt vector
ofs8 dw 0 ;offset
seg8 dw 0 ;segment
old_33 label DWORD ;Invoke "DOS 21 hex" interrupt vector
ofs33 dw 0 ;offset
seg33 dw 0 ;segment
old_34 label DWORD ;Terminate Address
ofs34 dw 0 ;offset
seg34 dw 0 ;segment
old_35 label DWORD ;Break Address
ofs35 dw 0 ;offset
seg35 dw 0 ;segment
old_36 label DWORD ;Critical Error Handler address
ofs36 dw 0 ;offset
seg36 dw 0 ;segment
;
; Install the interrupt handler for the timer (tick) interrupt.
;
; It contains a safeguard against overwriting the old_xx vectors
; so as to minimize the chances of getting the new values of
; the vectors saved, and thereby having this code locked into
; place forever.
;
PUBLIC _sl_von
IFDEF NEAR
_sl_von proc near ;for small memory models
ELSE
_sl_von proc far ;for large memory models
ENDIF
push es
push ds
mov ax,DGROUP ;actually, needed only for multisegment
mov ds,ax ;programs
cli ;disable maskable intertupts
;
; WARNING! The set_timer routine contains machine dependent code.
; It MAY NOT WORK on your machine.
;
call set_timer
;
; Do not replace vectors if they are already replaced.
;
test installed,0ffh ;vectors already installed?
jz noskip
jmp skipvec
noskip:
mov installed,0ffh
;
; Replace existing 'tick' interrupt (interrupt 8).
;
mov ax,cs
mov ds,ax
;
; Caution: these settings use ds=cs, not ds of this module's data!!!
;
mov ah,35h ;get interrupt vector
mov al,8 ;8
int 21h ;into ES:BX
mov seg8,es
mov ofs8,bx
mov dx,offset svc_timer
mov ah,25h ;set interrupt vector
mov al,8 ;8
int 21h ;from DS:DX
;
; Replace existing interrupt 33 (21 hex).
;
mov ah,35h ;get interrupt vector
mov al,33 ;33
int 21h ;into ES:BX
mov seg33,es
mov ofs33,bx
mov dx,offset do33
mov ah,25h ;set interrupt vector
mov al,33 ;33
int 21h
;
; Replace existing interrupt 34 (decimal).
;
mov ah,35h ;get interrupt vector
mov al,34 ;34
int 21h ;into ES:BX
mov seg34,es
mov ofs34,bx
mov dx,offset rest34
mov ah,25h ;set interrupt vector
mov al,34 ;34
int 21h
;
; Replace existing interrupt 35.
;
mov ah,35h ;get interrupt vector
mov al,35 ;35
int 21h ;into ES:BX
mov seg35,es ;:cs
mov ofs35,bx
mov dx,offset rest35
mov ah,25h ;set interrupt vector
mov al,35 ;35
int 21h
;
; Replace existing interrupt 36.
;
mov ah,35h ;get interrupt vector
mov al,36 ;36
int 21h ;into ES:BX
mov seg36,es ;:cs
mov ofs36,bx
mov dx,offset rest36
mov ah,25h ;set interrupt vector
mov al,36 ;36
int 21h
;
; Caution: ds is still cs here!
;
skipvec:
sti ;enable maskable interrupts
pop ds
pop es
ret
_sl_von ENDP
;
; This routine is entered when the program terminates, and is normally
; entered by way of one of the altered interrupts 33-36.
;
; It is permissible to call it more than once, since the saved vectors
; are not overwritten by anything.
;
PUBLIC _sl_voff
IFDEF NEAR
_sl_voff PROC near ;for small memory models
ELSE
_sl_voff PROC far ;for large memory models
ENDIF
push ds
push dx
push ax
mov ax,DGROUP
mov ds,ax
cli ;disable maskable interrupts
;
; Restore timer 0 to power-up value.
; WARNING! This code MAY NOT WORK on your machine.
;
mov al,36h
out 43h,al
mov al,0
out 40h,al
out 40h,al
;
; Cancel installation flag.
;
mov installed,0
;
; Caution: ds is obviously no good from here on down!
;
; Restore 'tick' interrupt (interrupt 8).
;
lds dx,old_8
mov ah,25h ;set interrupt vector
mov al,8 ;
int 21h
;
; Restore interrupt 33.
;
lds dx,old_33
mov ah,25h ;set interrupt vector
mov al,33 ;33
int 21h
;
; Restore interrupt 34.
;
lds dx,old_34 ;cs:old_34, of course
mov ah,25h ;set interrupt vector
mov al,34 ;34
int 21h
;
; Restore interrupt 35.
;
lds dx,old_35
mov ah,25h ;set interrupt vector
mov al,35 ;35
int 21h
;
; Restore interrupt 36.
;
lds dx,old_36
mov ah,25h ;set interrupt vector
mov al,36 ;36
int 21h
;
; Caution: ds is not valid here.
;
pop ax
pop dx
pop ds
sti
ret
;
; The following routines replace the original interrupt vectors 33-36.
; They simply de-install the timer interrupt (svc_timer) and then chain
; to the original interrupt vector.
;
; The do33 (dos 21 hex) interrupt is slightly more complicated.
; This is the DOS Functions software interrupt. All DOS functions except
; function 0 (terminate) and 4c hex (terminate process) are passed
; through unchanged. Functions 0 and 4c cause the timer interrupt to
; be de-installed.
;
do33:
cmp ah,4ch ;terminate process?
je rest33
cmp ah,0 ;terminate?
je rest33
jmp old_33 ;just pass through the request unchanged.
rest33:
call _sl_voff
jmp old_33
rest34:
call _sl_voff
jmp old_34
rest35:
call _sl_voff
jmp old_35
rest36:
call _sl_voff
jmp old_36
_sl_voff ENDP
;
; Service a timer interrupt.
;
; This code bumps the (long) sl_count counter defined in sherlock.c.
; Then, depending on the 'speed up factor', it either chains to the
; original 'tick' interrupt routine or returns from the interrupt
; immediately.
;
svc_timer PROC near
push ds
push ax
;
; The next statement has to use DGROUP, not _DATA, as the segment base.
; Ours is not to reason why...
;
; NOTE: even in a small-model program, the ds is apt not to be set
; correctly at the entry to svc_timer, since the int could occur
; from inside a utility or DOS function not part of the C program.
; In Microsoft C, the ds setting at the outset (__astart) isn't the
; same as the setting at _main, even for the small model!
;
mov ax,DGROUP
mov ds,ax
inc WORD PTR _sl_count
jnz svc_1
inc WORD PTR _sl_count+2
svc_1:
;
; See if we should chain to the original tick interrupt or
; return from the interrupt right away. This depends on the speed-up
; factor, i.e., the settings of sl_speed and timer_count.
;
dec timer_count
jnz skip
mov ax,timer_speed
mov timer_count,ax
cmp ax,_sl_speed
jz svc_2
call set_timer
;
; Chain to the original interrupt.
;
svc_2:
pop ax
pop ds
jmp old_8
;
; Return from the interrupt without chaining to the original interrupt.
;
skip:
mov al,20h
out 20h,al ;send EOI to 8259
pop ax
pop ds
iret ;return from interrupt
svc_timer ENDP
;
; Set up timer according to speed ratio.
; This needs to push all registers it uses, except ax.
;
; WARNING! This is MACHINE DEPENDENT CODE. There is NO guarantee
; that this code will work on your machine.
; If it does not work, you may just comment it all out, but
; then you will be stuck with the 18 hz. default clock rate.
;
set_timer PROC NEAR
push dx
mov ax,_sl_speed
cmp ax,0
jnz set_1
mov ax,1
set_1:
mov timer_speed,ax
mov timer_count,ax
mov ax,0ffffh
mov dx,0
div timer_speed ;sl_speed is a word, so it's 32:16
mov dx,ax ;dx = setting to be put into timer
mov al,36h ;timer 0, mode 3
out 43h,al
mov al,dl ;lsb
out 40h,al
mov al,dh ;msb
out 40h,al
pop dx
ret
set_timer ENDP
_TEXT ENDS
END